import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

/**
 * Vending Machine software, vends drinks and recipes
 * and tenders correct amount of change as well as 
 * tracks inventory.
 * @author Prince Kishore
 * @author Phat Le
 * @author Fahad Muzaffar
 * @version 1.4
 *
 */
class AcmeVendingMachine {

	static final int addSpaceToRecipeArray = 13;
	static Recipe re = new Recipe();

	static double money = 0;
	static double extra = 0;
	static double difference = 0;
	static int item = 0;
	static int totalDrinksSold = 0;
	private static int intNumber = 0;
	private static double doubleNumber = 0.0;
	private static final String MESSAGE_1= "Please enter an amount next time, going back to Main Menu";
	private static final String MESSAGE_2= "Whoops";
	private static final String MESSAGE_3= "Incorrect input, return to main menu.";
	
	/**
	 * Checks to see if passed input is an Int or not.
	 * @param line the int being passed in
	 * @param message1 Message saying that incorrect int was entered, going back to main menu.
	 * @param message2 Message saying that their is a number format exception.
	 * @return boolean value stating whether or not the input string is an input.
	 */
	static boolean checkInt(final String line, final String message1, final String message2){
		boolean check = false;
		setIntNumber(0);
		try{
			if(line == null){
				System.out.println(message1);
				mainMenu();
			} else {
					setIntNumber(Integer.parseInt(line));
					check = true;
			}
		} catch (NumberFormatException n) {
				System.out.println(message2);
				mainMenu();
		}
		return check;
	}
	
	/**
	 * Checks to see if passed input is a double.
	 * @param line the double being passed in
	 * @param message1 Message saying that incorrect double was entered, going back to main menu.
	 * @param message2 Message saying that their is a number format exception.
	 * @return boolean value stating whether or not the input string is an input.
	 */
	static boolean checkDouble(final String line, final String message1, final String message2){
		boolean check = false;
		setDoubleNumber(0.0);
		try{
			if(line == null){
				System.out.println(message1);
				mainMenu();
			} else {
					setDoubleNumber(Double.parseDouble(line));
					check = true;
			}
		} catch (NumberFormatException n) {
				System.out.println(message2);
				mainMenu();
		}
		return check;
	}
	
	
	/**
	 * Allows user to buy an item already created. Also asks
	 * for amount tendered and instructs user how much change
	 * to return.
	 */
	private static void BuyItem() {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("Please select item to buy: ");
		for(int n = 0; n < Recipe.recipeArray.length; n++){
			if(!Recipe.recipeArray[n].name.equals("")) {
			System.out.println(" " + n + ":  " + Recipe.recipeArray[n].name + "  $  "
							   + Recipe.recipeArray[n].price);
			}
			else 
				System.out.println(" " + n + ":" + "  No recipe.");
		}
		try{ 
			System.out.println("");
			checkInt(br.readLine(), MESSAGE_3, MESSAGE_3);
			item = getIntNumber();
			if(item > 5 || item < 0){
				System.out.println("Incorrect input, returning to main menu");
			mainMenu();
			}
			System.out.println(Recipe.recipeArray[item].name + "  $"  + Recipe.recipeArray[item].price);
			System.out.println("Please enter amount of money deposited: ");
			System.out.print("$  ");
			checkDouble(br.readLine(), MESSAGE_3, MESSAGE_3);
			money = getDoubleNumber();
		} catch (IOException e) {}
		checkItem();
	}//end BuyItem
		
	/**
	 * Checks item prices and amount tendered. Detects in insufficient funds,
	 * asks for difference giving two chances. Also detects insufficient 
	 * inventory and returns the appropriate change. Updates inventory,
	 * change, and drinks sold.
	 */
	private static void checkItem () {//
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		try{
	
			if(Inventory.checkInventorySufficience()){//
				//gets money
				difference = money - Recipe.recipeArray[item].price;
				
			}	
			else {  System.out.println("Insufficient inventory.");  			
					System.out.println("Change returned: " + money);
					mainMenu();
			}
			if(difference == 0){//
				System.out.println(Recipe.recipeArray[item].name + "   dispensed.\n");
				Recipe.recipeArray[item].timesSold += 1;
				totalDrinksSold = totalDrinksSold + 1;
			}// end ==0	
			if(difference > 0){//
				System.out.println("Change returned:  $" + difference);
				System.out.println(Recipe.recipeArray[item].name + " dispensed.\n");
				totalDrinksSold = totalDrinksSold + 1;
				Recipe.recipeArray[item].timesSold += 1;
			}//end >0
			if(difference < 0){//(1)
				difference = 0 - difference;
				System.out.println("Insufficient money deposited. Please deposit " + difference);
				difference = 0 - difference;
				System.out.println("Please enter amount:  ");
				System.out.print("$  ");
				checkDouble(br.readLine(), MESSAGE_3, MESSAGE_3);
				extra = getDoubleNumber();
				money += extra;
				difference = money - Recipe.recipeArray[item].price;
				while( difference <= 0 ) {
					if(difference == 0){
						System.out.println(Recipe.recipeArray[item].name + " dispensed.\n");
						totalDrinksSold = totalDrinksSold + 1;
						Recipe.recipeArray[item].timesSold += 1;
						break;
					}// end ==0	
					
					if(difference < 0) {//(2)
						System.out.println("Change returned:  " + money);
						System.out.println("Sorry, but you only get two chances."+
										   "\nReturning to Main Menu\n");
						mainMenu();
					}//end <0(2)
				}//end <0(1)
				
				if(difference > 0){//
						//difference = 0 - difference;
						System.out.println("Change returned:  $" + difference);
						System.out.println(Recipe.recipeArray[item].name + " dispensed.\n");
						totalDrinksSold = totalDrinksSold + 1;
						Recipe.recipeArray[item].timesSold += 1;
					}//end >0
			}				
		}catch(IOException e) {}
		Inventory.setUnitsSug(Inventory.getUnitsSug() - Recipe.recipeArray[item].sugar);
		Inventory.setUnitsMil(Inventory.getUnitsMil() - Recipe.recipeArray[item].milk);
		Inventory.setUnitsCof(Inventory.getUnitsCof() - Recipe.recipeArray[item].coffee);
		Inventory.setUnitsCho(Inventory.getUnitsCho() - Recipe.recipeArray[item].chocolate);
		Inventory.setUnitsBou(Inventory.getUnitsBou() - Recipe.recipeArray[item].bouillon);
		System.out.println("Thank You.");
		mainMenu();
	}//end checkItem
	
	/**
	 * Displays the amount of items sold as well as quantities and
	 * percentages of items sold.
	 */
	private static void CustomerAnalysis() {
		double percentSold = 0.0;
		System.out.println("Total drinks sold: " + totalDrinksSold);
		
		for(int i = 0; i < Recipe.recipeArray.length; i++){
			if(!Recipe.recipeArray[i].name.equals("")){
				if(totalDrinksSold > 0 ) {
					percentSold = (((double)Recipe.recipeArray[i].timesSold/(double)totalDrinksSold)*100);
					System.out.println("Item name:  " + Recipe.recipeArray[i].name + "  Quantity Sold:  " + Recipe.recipeArray[i].timesSold
								   +  "  % Sold:  " + percentSold );
					Recipe.recipeArray[i].timesSold = 0;
				}
				else {
					System.out.println("No " + Recipe.recipeArray[i].name + " have been bought at this time, returning to main menu.");
				}					
			}
		}
		totalDrinksSold = 0;
		mainMenu();
	}
	
	/**
	 * Invokes the main menu for the user to select options.
	 */
	public static void mainMenu() {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		System.out.println("\nPlease enter an action...");
		System.out.println("1 = Add Recipe");
		System.out.println("2 = Delete Recipe");
		System.out.println("3 = Add Inventory");
		System.out.println("4 = Check Inventory");
		System.out.println("5 = Buy Item");
		System.out.println("6 = Customer Analysis");
		System.out.println("7 = Exit\n");;
		System.out.print("=> ");

		try {
			checkInt(br.readLine(), MESSAGE_3, MESSAGE_3);
			if (getIntNumber() == 1) {
				Recipe.addRecipe();
			}
			if (getIntNumber() == 2) {
				Recipe.DeleteRecipe();
			}
			if (getIntNumber() == 3) {
				Inventory.AddInventory();
			}
			if (getIntNumber() == 4) {
				Inventory.checkInventory();
			}
			if (getIntNumber() == 5) {
				BuyItem();
			}
			if (getIntNumber() == 6) {
				CustomerAnalysis();
			}
			if (getIntNumber() == 7) {
				System.exit(0);
			} else {
				System.out.println("\nNot a valid selection, please choose again.\n");
				mainMenu();
			}
		} catch (IOException e) {
		}
	}// end mainMenu
	
	/**
	 * The program invokes main to initialize the rest of
	 * the program. Creates a title for the user and also
	 * created the recipe review. 
	 * @param arg invokation on main.
	 */
	public static void main (String[] arg) {
		title();
		for(int i =0; i<Recipe.recipeArray.length; i++){
			Recipe.recipeArray[i] = new Recipe();
		}
		mainMenu();	
	}
	
	/**
	 * Displays name of the program and version.
	 */
	private static void title()
	{
		System.out.println("\n\n\n");
		System.out.println("                     ACME VENDING MACHINE            ");
		System.out.println("                          version 1.2                ");
		System.out.println("\n\n\n");
	}

	/**
	 * Getter for Message1.
	 * @return the message1
	 */
	public static String getMessage1() {
		return MESSAGE_1;
	}
	
	/**
	 * Getter for Message2.
	 * @return the message2
	 */
	public static String getMessage2() {
		return MESSAGE_2;
	}
	
	/**
	 * Getter for Message3.
	 * @return the message3
	 */
	public static String getMessage3() {
		return MESSAGE_3;
	}

	/**
	 * Getter for IntNumber.
	 * @return the intNumber
	 */
	public static int getIntNumber() {
		return intNumber;
	}

	/**
	 * Sets the intNumber.
	 * @param intNumber the intNumber to set
	 */
	public static void setIntNumber(int intNumber) {
		AcmeVendingMachine.intNumber = intNumber;
	}
	
	/**
	 * Gets the doubleNumber.
	 * @return the doubleNumber
	 */
	public static double getDoubleNumber() {
		return doubleNumber;
	}

	/**
	 * Sets the doubleNumber.
	 * @param doubleNumber the doubleNumber to set
	 */
	public static void setDoubleNumber(double doubleNumber) {
		AcmeVendingMachine.doubleNumber = doubleNumber;
	}

	/**
	 * Gets the addSpaceToRecipeArray.
	 * @return the space to add to the recipeArray.
	 */
	public static int getAddspacetorecipearray() {
		return addSpaceToRecipeArray;
	}
}

